package com.jweb.framework.core.support;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.jweb.framework.core.ContextEx;
import com.jweb.framework.core.CoreRuntimeException;
import com.jweb.framework.core.Dispatcher;
import com.jweb.framework.core.channel.ChannelContext;
import com.jweb.framework.core.channel.ChannelInterceptor;
import com.jweb.framework.core.channel.Endpoint;
import com.jweb.framework.core.impl.DefaultContextEx;
import com.jweb.framework.core.service.ServiceRegistry;
import com.jweb.framework.core.util.GUID;

public class DefaultEndpoint<Request, Response> implements Endpoint<Request, Response>,BeanNameAware,ApplicationContextAware{

	private static GUID guid = new GUID();
	
	private static Logger logger = LoggerFactory.getLogger(DefaultEndpoint.class);
	
	private Dispatcher dispatcher ;
	
	private ChannelInterceptor<Request, Response> channelInterceptors[];
	
	private ServiceRegistry serviceRegistry ;
	
	private String channel ;
	
	private String beanName ;
	
	protected ApplicationContext applicationContext;
	
	public DefaultEndpoint(){
		
	}
	
	public void setApplicationContext(ApplicationContext applicationcontext) throws BeansException{
		applicationContext = applicationcontext;
	}
	
	/**
	 * @param channel the channel to set
	 */
	public void setChannel(String channel1) {
		this.channel = channel1;
	}
	
	protected ContextEx createContext(){
		
		DefaultContextEx defaultcontextex = new DefaultContextEx();
		defaultcontextex.setServiceRegistry(findServiceRegistry());
		defaultcontextex.setRequestId(guid.next().toString());
		if(channel != null){
			defaultcontextex.setAttribute("channel", channel);
		}
		
		return defaultcontextex ;
	}
	
	protected void checkContext(ContextEx contextEx) throws CoreRuntimeException{
		if(contextEx.getAttribute("PARAMETERS") == null){
			contextEx.setAttribute("PARAMETERS", contextEx.getDataMap());
		}
	}
	
	public void service(ChannelContext<Request, Response> channelcontext) throws CoreRuntimeException {
		
		ContextEx contextex;
		int i;
		Object obj;
		contextex = createContext();
		contextex.setChannelContext(channelcontext); // ��request����
		i = -1;
		obj = null;
		try {
			
			try {
				ChannelInterceptor achannelInterceptor[] ;
				/**
				 * ƽ̨�е���������Ҫ��Ϊ�����ļ��������������������������׼���������
				 * 		���У����ļ������������н�����ȫ������ʹ�õ���
				 *  	����������ֻ���ض������Ľ�����ʹ�ã�
				 *  	���׼�������������ģ���ڲ���������á�
				 *  
				 *  �˴����������ǣ���������������
				 */
				int k = (achannelInterceptor = channelInterceptors).length;  
				for(int j = 0 ; j < k ; j++){
					ChannelInterceptor channelInterceptor = achannelInterceptor[j];
					i ++ ;
					channelInterceptor.onRequest(channelcontext, contextex);
				}
				
				
			} catch (Throwable t) {
                logger.error("exception in request channel interceptors", t);
                throw t;
			}
			
			checkContext(contextex);
			findDispatcher().dispatch(contextex.getContext());
			
			
		} 
        catch(CoreRuntimeException cre)
        {
            obj = cre;
            throw cre;
        }
        catch(Error error)
        {
            obj = error;
            throw error;
        }
        catch(RuntimeException re)
        {
            obj = re;
            throw re;
        }
        catch(Throwable _ex)
        {	
        	obj = _ex ;
            throw new CoreRuntimeException("JAVACO0007", "uncaught exception, SHOULD happen!!!");
        } 
        finally {
        	for(int l = i ; l >= 0 ; l--){
            	ChannelInterceptor channelInterceptor1 = channelInterceptors[l];
            	channelInterceptor1.onResponse(channelcontext, contextex, (Throwable) obj);
            }
        }
		
      
	}
	
	public Dispatcher findDispatcher(){
		Dispatcher dis = dispatcher ;
		if(dis==null){
			dis = applicationContext.getBean(Dispatcher.class);
		}
		return dis ;
	}


	public void injectDispatcher(Dispatcher dispatcher1) {
		
		if(dispatcher1 == null){
			TRACER.trace("endpoint '{}' unbinding Dispatcher", new String[]{beanName});
		}
		else {
			TRACER.trace("endpoint '{}' binding Dispatcher" , new String[]{beanName});
		}
		dispatcher = dispatcher1;
	}

	public void injectServiceRegistry(ServiceRegistry serviceregistry) {
		
		if(serviceregistry == null){
			TRACER.trace("endpoint '{}' unbinding ServiceRegistry", new String[]{beanName});
		}
		else{
			TRACER.trace("endpoint '{}' binding ServiceRegistry ", new String[]{beanName});
		}
		
		serviceRegistry = serviceregistry ;
	}

	
	public void setInterceptors(ChannelInterceptor<Request, Response>[] arg0) {
		
		channelInterceptors = arg0;
	}
	

	public void setBeanName(String name) {
		
		beanName = name ;
		
	}

	public ServiceRegistry findServiceRegistry(){
		
		ServiceRegistry serviceregistry = serviceRegistry;
		
		if(serviceregistry==null){
			serviceregistry = applicationContext.getBean(ServiceRegistry.class);
		}
		
		return serviceregistry;  // "serviceregistry"=DefaultServiceRegistry
	}

	
	
	
}
